import GameNet from "./GameNet";
import { ProtocolPool } from "./protobufs/base/BaseProtocol";

const websocket = require("websocket");
const proto_man = require("proto_man");
const proto_tools = require("proto_tools");

export default class MsgAdapt {
    static offset: number = 0;
    static body: {} = {};
    static cmd_buf: DataView = null;

    static readBegin() {
        let cmd = {};
        cmd[0] = proto_tools.read_int16(this.cmd_buf, 0);
        cmd[1] = proto_tools.read_int16(this.cmd_buf, 2);
        this.offset = proto_tools.header_size;
    }

    static readStr() {
        let ret = proto_tools.read_str_inbuf(this.cmd_buf, this.offset);
        this.offset = ret[1];
        return ret[0];
    }

    static readNum() {
        let num = proto_tools.read_int16(this.cmd_buf, this.offset);
        this.offset += 2;
        return num;
    }

    static msgType: number = -1;
    static dataview: DataView = null;
    static datalist: any[] = [];

    static writeBegin(msgType: number) {
        this.msgType = msgType;
        let scType = MsgUtils.getStypeAndCtype(msgType);
        this.datalist.push(scType[0]);
        this.datalist.push(scType[1]);
        this.datalist.push(0);
    }

    static writeStr(str: string) {
        if (this.datalist.length < 3) return;
        this.datalist.push(str);
    }

    static writeNum(num: number) {
        if (this.datalist.length < 3) return;
        this.datalist.push(num);
    }

    /** 向服务端发送消息 */
    static send() {
        if (this.datalist.length < 3) return;
        let scType = MsgUtils.getStypeAndCtype(this.msgType);
        let msgLen = proto_tools.header_size;
        let totalLen = 0;
        for (let i = 3; i < this.datalist.length; ++i) {
            let value = this.datalist[i];
            switch (typeof (value)) {
                case `string`: {
                    totalLen += ((value as any).utf8_byte_len());
                    totalLen += 2;
                    break;
                }
                case `number`: {
                    totalLen += 2;
                    break;
                }
            }
        }
        totalLen += msgLen;
        this.dataview = proto_tools.alloc_buffer(totalLen);
        let offset = proto_tools.write_cmd_header_inbuf(this.dataview, scType[0], scType[1]);
        for (let i = 3; i < this.datalist.length; ++i) {
            let value = this.datalist[i];
            switch (typeof (value)) {
                case `string`: {
                    let len = (value as any).utf8_byte_len();
                    offset = proto_tools.write_str_inbuf(this.dataview, offset, value, len);
                    break;
                }
                case `number`: {
                    proto_tools.write_int16(this.dataview, offset, value);
                    offset += 2;
                    break;
                }
            }
        }
        websocket.send_encode_cmd(this.dataview);

        this.datalist = [];
        this.dataview = null;
    }

    /** 收到服务端消息 */
    static recv(msgType: number, body: DataView) {
        this.cmd_buf = body;
        GameNet.instance.onRecvMsg(msgType);
    }

    /** 注册回调 */
    static rigisterHandlers(msgType: number) {
        let stype = Math.floor(msgType / 100);
        let ctype = msgType % 100;

        let protocol = ProtocolPool.instance.getProtocolByType(msgType);

        proto_man.reg_buf_encoder(stype, ctype, protocol.encode.bind(protocol));
        proto_man.reg_buf_decoder(stype, ctype, (body) => {
            this.recv(msgType, body);
        });
    }
}

class MsgUtils {
    static getStype(msgType: number) {
        return Math.floor(msgType / 100);
    }

    static getCtype(msgType: number) {
        return msgType % 100;
    }

    static getStypeAndCtype(msgType: number) {
        return [this.getStype(msgType), this.getCtype(msgType)];
    }
}
